<template>
  <div class="midMesh" ref="midMeshRef"></div>
</template>

<script setup>
import { ref, watch, onMounted, onUnmounted } from "vue";
import * as THREE from "three";
import * as d3 from "d3-geo";

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

const midMeshRef = ref(null);

const props = defineProps({
  mapData: {
    type: Object,
    default: () => {},
  },
});

// 重命名变量避免命名冲突
const localMapData = ref(null);

let boxRef = ref(null);
let scene, camera, renderer, mesh, controls;
let animationFrameId;
// 创建纹理加载器
const textureLoader = new THREE.TextureLoader();
// 预加载纹理
const matcapTexture = textureLoader.load(
  "./model_assets/C7C7D7_4C4E5A_818393_6C6C74-512px.png"
);

watch(
  () => props.mapData,
  (newVal) => {
    if (newVal && Object.keys(newVal).length > 0) {
      localMapData.value = newVal;
      if (midMeshRef.value) {
        initThree();
      }
    }
  },
  {
    immediate: true,
    deep: true,
  }
);

// =================== 初始化地图 =================== //
const initThree = () => {
  console.log("初始化地图，使用数据:", localMapData.value);

  scene = new THREE.Scene();

  // 创建几何体
  // const geometry = new THREE.BoxGeometry(100, 100, 100);
  // const material = new THREE.MeshLambertMaterial({
  //   color: new THREE.Color("orange"),
  // });
  // mesh = new THREE.Mesh(geometry, material);
  // mesh.position.set(0, 0, 0);
  // scene.add(mesh);
  operationData(localMapData.value);

  // 创建光源
  const pointLight = new THREE.PointLight(0xffffff, 10000);
  pointLight.position.set(80, 80, 80);
  scene.add(pointLight);

  // 获取容器尺寸
  const container = midMeshRef.value;
  const width = container.clientWidth || window.innerWidth;
  const height = container.clientHeight || window.innerHeight;

  // 创建相机
  camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 1000);
  camera.position.set(0, 0, 30);
  camera.lookAt(0, 0, 0);

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({
    alpha: true,
    antialias: true,
    powerPreference: "high-performance",
  });
  renderer.setSize(width, height);

  container.appendChild(renderer.domElement);

  // 创建控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;

  // 模型加载完成后，调用居中函数
  centerMap();

  window.addEventListener("resize", onWindowResize);

  // 启动渲染循环
  animate();
};

// 修改中心 墨卡托转换 经纬度坐标转换
const projection = d3
  .geoMercator()
  .center([118.767413, 32.041544])
  .translate([0, 0]);

/**
 * 数据处理
 * @param {*} jsonData 地图数据
 */
const map = new THREE.Object3D();
const operationData = (jsonData) => {
  const features = jsonData.features;

  features.forEach((feature) => {
    // 单个省份
    const province = new THREE.Object3D();

    // 数据整合
    province.properties = feature.properties.name;
    const coordinates = feature.geometry.coordinates;

    // 多个多边形
    if (feature.geometry.type === "MultiPolygon") {
      coordinates.forEach((coordinate) => {
        coordinate.forEach((rows) => {
          const mesh = drawExtrudeMesh(rows);
          // const line = lineDraw(rows, color);
          province.add(mesh);
          // province.add(line);
        });
      });
    }

    // 单个多边形
    if (feature.geometry.type === "Polygon") {
      coordinates.forEach((coordinate) => {
        const mesh = drawExtrudeMesh(coordinate);
        // const line = lineDraw(coordinate, color);
        province.add(mesh);
        // province.add(line);
      });
    }

    map.add(province);
  });

  scene.add(map);
};

/**
 * 居中地图模型
 * 计算模型边界盒，调整相机位置和控制器目标使模型居中
 */
const centerMap = () => {
  if (!map || !scene || !camera || !controls) return;

  // 创建边界盒子并计算模型范围
  const box = new THREE.Box3().setFromObject(map);
  const size = box.getSize(new THREE.Vector3());
  const center = box.getCenter(new THREE.Vector3());

  // 计算合适的相机距离，确保模型完全可见
  const maxDim = Math.max(size.x, size.y, size.z);
  const fov = camera.fov * (Math.PI / 180);
  let cameraDistance = maxDim / (2 * Math.tan(fov / 2));

  // 添加额外的距离，确保模型完全可见
  cameraDistance *= 1.2;

  // 更新相机位置，保持原有的观察方向但调整距离
  const direction = new THREE.Vector3(0, 0, 1).normalize();
  const cameraPosition = direction.multiplyScalar(cameraDistance).add(center);
  camera.position.copy(cameraPosition);

  // 让相机看向模型中心
  camera.lookAt(center);

  // 更新控制器目标为模型中心
  controls.target.copy(center);
  controls.update();

  console.log("地图已居中，中心点:", center, "尺寸:", size);
};

/**
 * 绘制立体几何
 * @param {*} polygon 多边形 点数组
 */
const drawExtrudeMesh = (polygon) => {
  const shape = new THREE.Shape();

  polygon.forEach((row, i) => {
    const [x, y] = projection(row);

    if (i === 0) {
      shape.moveTo(x, -y);
    }
    shape.lineTo(x, -y);
  });

  // 挤压缓冲几何
  const geometry = new THREE.ExtrudeGeometry(shape, {
    depth: 1.3, // 挤压高度
    bevelEnabled: false, // 对挤出形状应用是否斜角
  });

  const material = new THREE.MeshMatcapMaterial({
    matcap: matcapTexture,
  });

  return new THREE.Mesh(geometry, material);
};

/**
 * 绘制边框 线
 * @param {*} polygon 多边形 点数组
 * @param {*} color 材质颜色
 */
const lineDraw = (polygon, color) => {
  const lineGeometry = new THREE.BufferGeometry();
  const pointsArray = new Array();

  polygon.forEach((row) => {
    const [x, y] = projection(row);
    pointsArray.push(new THREE.Vector3(x, -y, 1));
  });
  lineGeometry.setFromPoints(pointsArray);

  const lineMaterial = new THREE.LineBasicMaterial({
    color: color,
    linewidth: 6,
  });

  return new THREE.Line(lineGeometry, lineMaterial);
};

// =================== 渲染循环 =================== //
const animate = () => {
  animationFrameId = requestAnimationFrame(animate);

  // 添加旋转动画，使几何体更加明显
  // if (mesh) {
  //   mesh.rotation.x += 0.01;
  //   mesh.rotation.y += 0.01;
  // }

  // 更新控制器
  controls.update();

  // 渲染场景
  if (renderer && scene && camera) {
    renderer.render(scene, camera);
  }
};

// =================== 窗口大小变化时，更新相机和渲染器 =================== //
const onWindowResize = () => {
  if (!midMeshRef.value) return;

  const container = midMeshRef.value;
  const width = container.clientWidth || window.innerWidth;
  const height = container.clientHeight || window.innerHeight;

  if (!camera || !renderer) return;

  camera.aspect = width / height;
  camera.updateProjectionMatrix();

  renderer.setSize(width, height);

  // 窗口大小变化时重新居中模型
  centerMap();
};

// =================== 挂载组件时，初始化地图 ================================== //
onMounted(() => {
  if (localMapData.value && Object.keys(localMapData.value).length > 0) {
    initThree();
  }
});

// =================== 卸载组件时，取消动画帧，释放渲染器资源 =================== //
onUnmounted(() => {
  cancelAnimationFrame(animationFrameId);
  if (renderer) {
    renderer.dispose();
  }
  window.removeEventListener("resize", onWindowResize);
});
</script>

<style lang="scss" scoped>
.midMesh {
  width: 100%;
  height: 100%;
}
</style>
